
const { ccclass, property } = cc._decorator;

/**
 * 此脚本加在scroll根节点
 * view anchor设置为(0, 1);
 * content anchor设置为(0, 1);
 * 每个item大小一样
 */
@ccclass
export default class ScrollGridView extends cc.Component {

    @property(cc.Prefab)
    itemPrefab: cc.Prefab = null;

    @property(cc.Node)
    contentNode: cc.Node = null;

    @property()
    paddingLeft = 0;
    @property()
    paddingRight = 0;
    @property()
    paddingTop = 0;
    @property()
    paddingBottom = 0;

    @property()
    spacingX = 0;
    @property()
    spacingY = 0;

    //渲染事件（渲染器）
    @property({
        type: cc.Component.EventHandler,
        tooltip: CC_DEV && '渲染事件（渲染器）',
    })
    private renderEvent: cc.Component.EventHandler = new cc.Component.EventHandler();


    //渲染事件（渲染器）
    @property({
        type: cc.Component.EventHandler,
        tooltip: CC_DEV && '创建事件（渲染器）',
    })
    private createEvent: cc.Component.EventHandler = new cc.Component.EventHandler();

    private _itemCount = 0;
    set itemCount(count: number) {
        this._itemCount = count;
        if (this._loaded == false)
            return;
        this.lastStartIndex = -1;
        this.lastEndIndex = -1;
        this.updateContentSize();
        this.generatePoints();
        this.updateDisplay();
    }

    get itemCount() {
        return this._itemCount;
    }

    _pool: cc.NodePool = new cc.NodePool();
    //单个物品的size,此处是需要每个item同size;
    _itemSize: cc.Size = null;

    _viewNode: cc.Node = null;
    _viewSize: cc.Size;
    _colNum = 0;

    _itemPositions: cc.Vec2[] = [];

    _loaded = false;

    _scrollViewComp: cc.ScrollView = null;

    onLoad() {
    }

    start() {
        let item = cc.instantiate(this.itemPrefab);
        this._itemSize = item.getContentSize();
        this._viewNode = this.contentNode.parent;
        this._viewSize = this._viewNode.getContentSize();
        //TOOD此处假设以垂直滑动
        let nopaddingwidth = this._viewSize.width - this.paddingLeft - this.paddingRight;
        this._colNum = Math.floor((nopaddingwidth + this.spacingX) / (this._itemSize.width + this.spacingX));

        this._loaded = true;

        if (this._itemCount > 0) {
            this.itemCount = this._itemCount;
        }
        this._scrollViewComp = this.node.getComponent(cc.ScrollView);

        this.schedule(this.updateDisplay, 0.06);
    }

    //生成并保存节点坐标
    private generatePoints() {
        if (this._itemPositions.length >= this._itemCount)
            return;
        for (let i = this._itemPositions.length; i < this._itemCount; ++i) {
            this._itemPositions.push(this.calItemPosition(i));
        }
    }

    private updateContentSize() {
        let rowCount = Math.ceil(this._itemCount / this._colNum);
        let contentY = this.paddingTop + this.paddingBottom + (rowCount - 1) * this.spacingY + rowCount * this._itemSize.height;
        let contentX = this.contentNode.width;
        this.contentNode.setContentSize(cc.size(contentX, Math.max(this._viewSize.height, contentY)));
    }

    lastStartIndex = -1;
    lastEndIndex = -1;
    private updateDisplay() {
        let startIndex = -1;
        //找到最上面的显示起点
        for (let i = 0; i < this._itemCount; i += this._colNum) {
            //下边缘如果在view内，则此结点需要显示
            let yBottom = this._itemPositions[i].y - this._itemSize.height * 0.5;
            if (yBottom + this.contentNode.y <= 0) {
                startIndex = i;
                break;
            }
        }
        //找到最下排的显示起点
        let endIndex = startIndex;
        for (let i = startIndex + this._colNum; i < this.itemCount && startIndex > -1; i += this._colNum) {
            //上边缘如果在view内，则此结点需要显示
            let yTop = this._itemPositions[i].y + this._itemSize.height * 0.5;
            if (yTop + this.contentNode.y < -this._viewSize.height) {
                break;
            }
            endIndex = i;
        }

        if (startIndex == this.lastStartIndex && endIndex == this.lastEndIndex) {
            return;
        }
        // console.log(`起点:${startIndex}, 终点:${endIndex}, 上次起点:${this.lastStartIndex}, 上次结点:${this.lastEndIndex}`)
        this.lastStartIndex = startIndex;
        this.lastEndIndex = endIndex;
        if (startIndex > -1) {
            let realEndIndex = Math.min(endIndex + this._colNum , this._itemCount) 
            let children = this.contentNode.children;
            for (let i = children.length - 1; i >= 0; --i) {
                let c = children[i];
                let idx = c["idx"] != null ? c['idx'] : -1;
                if (idx < startIndex || idx >= realEndIndex) {
                    this._pool.put(c);
                }
            }
            for (let i = startIndex; i < realEndIndex; ++i) {
                let child = this.contentNode.getChildByName(i.toString());
                if (child == null) {
                    child = this.createItemNode();
                    child.name = i.toString();
                    child.position = cc.v3(this._itemPositions[i]);
                    child.parent = this.contentNode;
                    child['idx'] = i;
                }
                if (this.renderEvent) {
                    cc.Component.EventHandler.emitEvents([this.renderEvent], child, i);
                }
            }
            // console.log(`节点数目:${this.contentNode.childrenCount}`)
        }
    }

    //idx从0开始
    private calItemPosition(idx: number) {
        let c = idx % this._colNum;
        let r = Math.floor(idx / this._colNum);
        //此处假设anchor = cc.v2(0.5, 0.5);
        let x = this.paddingLeft + c * this.spacingX + (c + 0.5) * this._itemSize.width;
        let y = this.paddingTop + r * this.spacingY + (r + 0.5) * this._itemSize.height;
        return cc.v2(x, -y)
    }

    createItemNode() {
        if (this._pool.size() > 0) {
            return this._pool.get();
        }
        let item = cc.instantiate(this.itemPrefab);
        if (this.createEvent) {
            cc.Component.EventHandler.emitEvents([this.createEvent], item);
        }
        return item;
    }

}
